import tkinter as tk
from tkinter import ttk
import random
import threading
import os
import numpy as np
import requests  # 添加requests库导入

class SugarReductionApp:
    def __init__(self, root):
        # 初始化主窗口
        self.root = root  # 将传入的根窗口对象赋值给self.root
        self.root.title("果糖含量检测与减糖预估")  # 设置窗口标题
        self.root.geometry("800x600")  # 设置窗口大小
        self.create_widgets()  # 调用create_widgets方法创建窗口中的控件
        # 控制最多同时运行10个线程
        self.semaphore = threading.Semaphore(10)  # 创建一个信号量对象，限制最多同时运行10个线程

    def create_widgets(self):
        # 创建标签和输入框的方法
        def create_label_and_entry(label_text, row, text_var):
            ttk.Label(self.root, text=label_text).grid(column=0, row=row, padx=10, pady=5)  # 创建标签并放置在指定位置
            ttk.Entry(self.root, textvariable=text_var).grid(column=1, row=row, padx=10, pady=5)  # 创建输入框并放置在指定位置

        # 用户身高
        self.height_var = tk.StringVar()  # 创建一个StringVar对象，用于存储用户身高
        create_label_and_entry("用户身高 (cm):", 3, self.height_var)  # 调用create_label_and_entry方法创建标签和输入框

        # 用户体重
        self.weight_var = tk.StringVar()  # 创建一个StringVar对象，用于存储用户体重
        create_label_and_entry("用户体重 (kg):", 4, self.weight_var)  # 调用create_label_and_entry方法创建标签和输入框

        # 用户性别
        self.gender_var = tk.StringVar(value="男")  # 创建一个StringVar对象，默认值为"男"
        ttk.Label(self.root, text="用户性别:").grid(column=0, row=5, padx=10, pady=5)  # 创建标签并放置在指定位置
        ttk.Combobox(self.root, textvariable=self.gender_var, values=["男", "女"]).grid(column=1, row=5, padx=10, pady=5)  # 创建下拉框并放置在指定位置

        # BMI
        self.bmi_var = tk.StringVar()  # 创建一个StringVar对象，用于存储BMI值
        ttk.Label(self.root, text="BMI:").grid(column=0, row=6, padx=10, pady=5)  # 创建标签并放置在指定位置
        ttk.Entry(self.root, textvariable=self.bmi_var, state='readonly').grid(column=1, row=6, padx=10, pady=5)  # 创建只读输入框并放置在指定位置

        # 计算BMI按钮
        ttk.Button(self.root, text="计算BMI", command=self.calculate_bmi).grid(column=2, row=4, padx=10, pady=5)
        ttk.Button(self.root, text="获取建议", command=self.threaded_get_advice).grid(column=2, row=5, padx=10, pady=5)  # 创建按钮并放置在指定位置，点击时调用calculate_bmi方法

        # 日志框
        ttk.Label(self.root, text="日志:").grid(column=0, row=7, padx=10, pady=5)  # 创建标签并放置在指定位置
        self.log_text = tk.Text(self.root, height=15, width=80)  # 创建文本框用于显示日志
        self.log_text.grid(column=0, row=8, columnspan=3, padx=10, pady=5)  # 将文本框放置在指定位置

        # 营养建议显示框
        ttk.Label(self.root, text='营养建议:').grid(column=0, row=9, padx=10, pady=5)
        self.advice_text = tk.Text(self.root, height=4, width=80)
        self.advice_text.grid(column=0, row=10, columnspan=3, padx=10, pady=5)

        ttk.Button(self.root, text="随机生成数据", command=self.generate_random_data).grid(column=2, row=7, padx=10, pady=5)



    def calculate_bmi(self):
        try:
            # 获取用户输入的身高和体重并计算BMI
            height = float(self.height_var.get()) / 100  # 将身高从厘米转换为米
            weight = float(self.weight_var.get())  # 获取体重
            bmi = weight / (height ** 2)  # 计算BMI 
            self.bmi_var.set(f"{bmi:.2f}")  # 将BMI值设置为输入框的内容
        except ValueError:
            self.bmi_var.set("输入无效")  # 如果输入无效，设置输入框内容为"输入无效"

    def generate_random_data(self):
        # 定义果汁种类及其果糖含量范围
        fruits = {
            "哈密瓜": (1.8, 2.5),  # 哈密瓜的果糖含量范围
            "苹果": (5.9, 7.5),  # 苹果的果糖含量范围
            "草莓": (2.0, 2.5),  # 草莓的果糖含量范围
            "蓝莓": (4.9, 5.5),  # 蓝莓的果糖含量范围
            "香蕉": (4.9, 5.5),  # 香蕉的果糖含量范围
            "梨子": (6.0, 7.0),  # 梨子的果糖含量范围
            "桃子": (1.5, 2.0),  # 桃子的果糖含量范围
            "柠檬": (0.6, 1.0),  # 柠檬的果糖含量范围
            "桑葚": (4.3, 5.0),  # 桑葚的果糖含量范围
            "葡萄": (7.2, 8.0),  # 葡萄的果糖含量范围
            "橙子": (2.4, 3.0),  # 橙子的果糖含量范围
            "菠萝": (2.0, 2.5),  # 菠萝的果糖含量范围
            "猕猴桃": (4.0, 5.0),  # 猕猴桃的果糖含量范围
            "西瓜": (3.0, 3.5),  # 西瓜的果糖含量范围
            "火龙果": (3.0, 4.0),  # 火龙果的果糖含量范围
            "芒果": (4.7, 5.5),  # 芒果的果糖含量范围
            "荔枝": (6.0, 7.0),  # 荔枝的果糖含量范围
            "杨梅": (3.0, 4.0)  # 杨梅的果糖含量范围
        }

        # 根据性别生成合理的身高和体重
        def get_height_and_weight(gender):
            if gender == "男":
                height = np.random.normal(175, 12)  # 生成男性身高，均值为175，标准差为12
                bmi = np.random.normal(23.3, 2.5)  # 生成男性BMI，均值为23.3，标准差为2.5
            else:
                height = np.random.normal(162, 6)  # 生成女性身高，均值为162，标准差为6
                bmi = np.random.normal(22.7, 2.5)  # 生成女性BMI，均值为22.7，标准差为2.5
            weight = bmi * (height / 100) ** 2  # 根据BMI和身高计算体重
            return round(height), round(weight)  # 返回四舍五入后的身高和体重

        log_entries = []  # 创建一个空列表，用于存储日志条目

        for _ in range(10):
            with self.semaphore:  # 使用信号量控制线程并发数量
                juice, (min_fructose, max_fructose) = random.choice(list(fruits.items()))  # 随机选择一种果汁及其果糖含量范围
                fructose = random.uniform(min_fructose, max_fructose)  # 在范围内随机生成果糖含量
                gender = random.choice(["男", "女"])  # 随机选择性别
                height, weight = get_height_and_weight(gender)  # 根据性别生成身高和体重
                reduced_fructose = fructose * random.uniform(0.56, 0.58)  # 计算减糖后的果糖含量
                bmi = weight / ((height / 100) ** 2)  # 计算BMI

                log_entry = (
                    f"果汁种类: {juice}, "
                    f"果糖含量: {fructose:.2f}g, "
                    f"减糖后果糖含量: {reduced_fructose:.2f}g, "
                    f"身高: {height}cm, "
                    f"体重: {weight}kg, "
                    f"性别: {gender}, "
                    f"BMI: {bmi:.2f}\n"
                )

                # 将日志条目插入日志区域
                self.root.after(0, self.log_text.insert, tk.END, log_entry)
                # 将日志条目添加到列表中
                log_entries.append(log_entry)

        # 将日志条目追加到txt文件
        self.root.after(0, self.append_to_log_file, log_entries)

    def threaded_get_advice(self):
        threading.Thread(target=self.get_nutrition_advice, daemon=True).start()

    def get_nutrition_advice(self):
        api_key = "sk-ee0bd93942104d4187aa37ff6f7f6fef"  # 硬编码API密钥
        if not api_key:
            self.root.after(0, self.show_error, '请设置API密钥')
            return

        prompt = f"用户身高：{self.height_var.get()}cm，体重：{self.weight_var.get()}kg，性别：{self.gender_var.get()}，BMI：{self.bmi_var.get()}。请给出果汁饮用建议"
        
        try:
            response = requests.post(
                'https://api.deepseek.com/v1/chat/completions',
                headers={'Authorization': f'Bearer {api_key}', 'Content-Type': 'application/json'},
                json={'model': 'deepseek-chat', 'messages': [{'role': 'user', 'content': prompt}]}
            )
            response.raise_for_status()
            advice = response.json()['choices'][0]['message']['content']
            self.root.after(0, self.update_advice, advice)
        except Exception as e:
            self.root.after(0, self.show_error, f'API错误: {str(e)}')

    def update_advice(self, text):
        self.advice_text.delete(1.0, tk.END)
        self.advice_text.insert(tk.END, text)

    def show_error(self, message):
        messagebox.showerror("错误", message)

    def append_to_log_file(self, entries):
        with open(os.path.join(os.getcwd(), "log_entries.txt"), "a", encoding="utf-8") as file:
            file.writelines(entries)

if __name__ == "__main__":
    # 创建主窗口
    root = tk.Tk()
    # 初始化程序逻辑
    app = SugarReductionApp(root)
    # 启动事件循环
    root.mainloop()